Modelling report

Are there unconscious visual images in aphantasia? Development of an implicit priming paradigm


# Packages ----------------------------------------------------------------

# using a reproducible environment
renv::restore()

# the cmdstanr package for Bayesian modelling has to be installed manually
# install.packages(
#   "cmdstanr", 
#   repos = c('https://stan-dev.r-universe.dev', getOption("repos")))

# The cmdstan backend, if not already installed, has to be installed on your 
# computer first, outside of the project:
# check_cmdstan_toolchain() # check if RTools is setup
# nb_cores <- parallel::detectCores() - 1
# install_cmdstan(cores = nb_cores)

# pacman allows to check/install/load packages with a single call
# if (!require("pacman")) install.packages("pacman") # already in renv.lock
library("pacman")

# packages to load (and install if needed) -------------------------------
pacman::p_load(
  here,      # easy file paths
  see,       # theme_modern and okabeito palette
  report,    # reporting various info 
  labelled,  # labelled data
  quarto,
  # ---- Modelling
  easystats, # modelling package framework
  lme4,      # mixed-effects models
  car,       # companion to lme4
  simr,      # power analysis
  statmod,   # power analysis
  emmeans,   # post-hoc tests
  # ---- Bayesian modelling
  brms,      # Bayesian regression models
  tidybayes, # tidy output for brms
  bayesplot, # Bayesian visualisations
  cmdstanr,  # Stan interface
  
  # ---- Visualisations
  qqplotr,    # QQ plots
  scales,     # ggplot2 scales
  latex2exp,  # LaTeX expressions in ggplot2
  ggbeeswarm, # beeswarm plots
  ggpubr,     # publication-ready plots
  patchwork,  # combining plots
  # ---- Data wrangling
  readxl,
  openxlsx,
  tidyverse  # modern R ecosystem
)


# Custom functions shared across scripts ----------------------------------
source(here("scripts/_functions.R"))


# Global cosmetic theme ---------------------------------------------------

theme_set(theme_modern(base_size = 14)) # from see in easystats

# setting my favourite palettes as ggplot2 defaults
options( 
  ggplot2.discrete.colour   = scale_colour_okabeito,
  ggplot2.discrete.fill     = scale_fill_okabeito,
  ggplot2.continuous.colour = scale_colour_viridis_c,
  ggplot2.continuous.fill   = scale_fill_viridis_c
)


# Fixing a seed for reproducibility ---------------------------------------
set.seed(14051998)


# Adding all packages' citations to a .bib --------------------------------
knitr::write_bib(c(.packages()), file = here("bibliography/packages.bib"))

1 Questionnaires analyses

1.1 Group differences

Table

Questionnaire yes no df t p
VVIQ 19.083 ± 0.913 54.188 ± 1.095 148 -21.24 8.65e-47
OSIQ_Object 23.924 ± 0.994 46.561 ± 1.192 148 -13.29 5.07e-27
OSIQ_Spatial 41.011 ± 0.865 45.452 ± 1.036 148 -3.40 8.58e-04
SUIS 17.335 ± 0.749 37.132 ± 0.898 148 -15.51 7.75e-33

Plot

Code
df_q_norm |> 
  
  # -------------------------- Long format first
  pivot_longer(
    cols = c(VVIQ:SUIS),
    names_to = "Questionnaire",
    values_to = "Score"
  ) |>
  mutate(
    Questionnaire = fct_relevel(
      Questionnaire, 
      c("VVIQ", "SUIS", "OSIQ_Object", "OSIQ_Spatial")
    )) |> 
  
  # -------------------------- Plotting
  ggplot(aes(
    x = Questionnaire, 
    y = Score, 
    fill = aphantasia, 
    color = aphantasia
    )) +
  
  # accentuation of the median line at 0.5
  geom_hline(
    yintercept = .5,
    linetype = 1,
    color = "grey30",
    alpha = .2
  ) +
  
  # --------------------- Scores
  # violin shapes for the distributions and quantiles
  geom_violin(
    position = position_dodge(dw),
    alpha = .1,
    draw_quantiles = c(.25, .5, .75)
  ) +
  # points for means and lines for CIs
  geom_pointrange(
    data = norm_means,
    aes(
      x = Questionnaire,
      y = Mean,
      ymin = CI_low,
      ymax = CI_high,
      color = aphantasia
    ),
    size = .75,
    linewidth = 1,
    position = position_dodge(dw)
  ) +
  
  # --------------------- Stars and lines
  # stars for significance
  annotate(
    geom  = "text", label = "***", color = "black",
    x = 1, y = .95, size  = 10 
    ) +
  # dotted line that separates the different questionnaires
  geom_vline(
    aes(xintercept = stage(Questionnaire, after_scale = 1.5)),
    linetype = 3
  ) +
  # stars 
  annotate(
    geom  = "text", label = "***", color = "black",
    x = 2, y = .95, size  = 10 
    ) +
  # dotted line
  geom_vline(
    aes(xintercept = stage(Questionnaire, after_scale = 2.5)),
    linetype = 3
  ) +
  # stars
  annotate(
    geom  = "text", label = "***", color = "black",
    x = 3, y = .95, size  = 10 
    ) +
  # dotted line
  geom_vline(
    aes(xintercept = stage(Questionnaire, after_scale = 3.5)),
    linetype = 3
  ) +
  # stars
  annotate(
    geom  = "text", label = "***", color = "black",
    x = 4, y = .95, size  = 10 
    ) +
  
  # --------------------- Aesthetics
  scale_color_okabeito(name = "Group:  ", labels = c(" Control   ", " Aphantasia")) +
  scale_fill_okabeito(name = "Group:  ", labels  = c(" Control   ", " Aphantasia")) +
  scale_x_discrete(
    name = "",
    labels = c("VVIQ", "SUIS", "OSIQ-Object", "OSIQ-Spatial")
  ) +
  scale_y_continuous(
    name = "Standardized score",
    breaks = breaks_pretty(8)
  ) +
  theme(
    panel.grid.major.x = element_blank(),
    panel.grid.major.y = element_line(),
    axis.text.x  = element_text(size = txt),
    axis.title.y = element_text(size = txt),
    legend.title = element_text(size = txt_legend),
    legend.text  = element_text(size = txt_legend),
    legend.position = "top"
    )
Code
ggsave(here("figures/questionnaires.png"), dpi = 600)

Figure S1.1

1.2 Congruence effects correlations

Matrices

Code
corr <- 
  df_questionnaires |> 
    select(aphantasia, "Implicit effect":"SUIS") |>
    correlation(method = "spearman", p_adjust = "fdr") 

corr
# Correlation Matrix (spearman-method)

Parameter1      |      Parameter2 |   rho |        95% CI |        S |         p
--------------------------------------------------------------------------------
Implicit effect | Explicit effect |  0.05 | [-0.11, 0.21] | 5.44e+05 | 0.571    
Implicit effect |            VVIQ |  0.21 | [ 0.05, 0.37] | 4.51e+05 | 0.016*   
Implicit effect |     OSIQ_Object |  0.26 | [ 0.10, 0.40] | 4.27e+05 | 0.003**  
Implicit effect |    OSIQ_Spatial |  0.05 | [-0.11, 0.21] | 5.44e+05 | 0.571    
Implicit effect |            SUIS |  0.27 | [ 0.11, 0.41] | 4.21e+05 | 0.002**  
Explicit effect |            VVIQ |  0.08 | [-0.09, 0.24] | 5.29e+05 | 0.427    
Explicit effect |     OSIQ_Object |  0.12 | [-0.04, 0.28] | 5.03e+05 | 0.194    
Explicit effect |    OSIQ_Spatial | -0.02 | [-0.18, 0.15] | 5.84e+05 | 0.831    
Explicit effect |            SUIS |  0.16 | [ 0.00, 0.32] | 4.82e+05 | 0.081    
VVIQ            |     OSIQ_Object |  0.76 | [ 0.68, 0.82] | 1.40e+05 | < .001***
VVIQ            |    OSIQ_Spatial |  0.28 | [ 0.13, 0.43] | 4.11e+05 | 0.001**  
VVIQ            |            SUIS |  0.84 | [ 0.79, 0.88] | 89975.33 | < .001***
OSIQ_Object     |    OSIQ_Spatial |  0.09 | [-0.07, 0.25] | 5.20e+05 | 0.341    
OSIQ_Object     |            SUIS |  0.82 | [ 0.75, 0.86] | 1.06e+05 | < .001***
OSIQ_Spatial    |            SUIS |  0.30 | [ 0.15, 0.45] | 3.99e+05 | < .001***

p-value adjustment method: Benjamini & Hochberg (1995)
Observations: 151
Code
corr |> summary() |> plot() + 
  labs(title = "Correlation matrix, whole group (Spearman FDR corrected)")
Code
# ggsave(here("figures/corr-mat-whole.png"), dpi = 600)

Figure S1.2

Plots

Code
layout <- "
AAAABBBB
##CCCC##
"

# ((p_corr_vviq + p_corr_osiq) / p_corr_suis) +
(p_corr_vviq + p_corr_osiq + p_corr_suis) +
  plot_layout(design = layout, guides = "collect") &
  theme(
    legend.position = "top", 
    legend.text = element_text(size = 20),
    legend.title = element_blank(),
    axis.title = element_text(size = 16)
    )
Code
# ggsave(here("figures/corr-plots.png"), dpi = 600)

Figure S1.3

2 Accuracy analyses

We quickly checked for accuracy differences between groups with a logistic regression model.

Code
fit_acc_im <- 
  glmer(
    formula = correct_implicit ~ (aphantasia + congruence + color)^3 + (1 | subjectid),
    data = df_i_acc,
    family = binomial(link = "logit"),
  control = glmerControl(optimizer = "bobyqa")
  )

fit_acc_ex <- 
  glmer(
    formula = correct_explicit ~ (aphantasia + congruence + color)^3 + (1 | subjectid),
    data = df_e_acc,
    family = binomial(link = "logit"),
    control = glmerControl(optimizer = "bobyqa")
  )
Table S2.1: Performance and estimates of the logistic GLMM fitted on accuracy in the implicit task.
AIC AICc BIC R2 (cond.) R2 (marg.) ICC RMSE Sigma Log_loss Score_log
2614.99 2615.01 2679.02 0.17 9.48e-03 0.16 0.18 1.00 0.13 -Inf
Analysis of Deviance Table (Type II Wald chisquare tests)

Response: correct_implicit
                             Chisq Df Pr(>Chisq)  
aphantasia                  1.1704  1    0.27932  
congruence                  0.2858  1    0.59296  
color                       6.3683  1    0.01162 *
aphantasia:congruence       0.2986  1    0.58479  
aphantasia:color            0.5591  1    0.45463  
congruence:color            0.0163  1    0.89851  
aphantasia:congruence:color 0.5143  1    0.47327  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Table S2.2: Estimated probability of a correct answer and log-odds contrasts between groups for the accuracy in the implicit task.
Estimated Marginal Means
color Probability SE 95% CI
Uncoloured 0.97 3.37e-03 (0.96, 0.98)
Coloured 0.98 2.70e-03 (0.97, 0.98)

Marginal means estimated at color

Marginal Contrasts Analysis
Level1 Level2 Odds ratio 95% CI SE df z p
Uncoloured Coloured 0.73 (0.58, 0.92) 0.09 Inf -2.63 0.009

Marginal contrasts estimated at color p-values are uncorrected.

Table S2.3: Performance and estimates of the logistic GLMM fitted on accuracy in the explicit task.
AIC AICc BIC R2 (cond.) R2 (marg.) ICC RMSE Sigma Log_loss Score_log
2020.26 2020.28 2084.03 0.18 0.03 0.16 0.15 1.00 0.11 -Inf
Analysis of Deviance Table (Type II Wald chisquare tests)

Response: correct_explicit
                              Chisq Df Pr(>Chisq)    
aphantasia                   1.5712  1     0.2100    
congruence                   0.2753  1     0.5998    
color                       18.9615  1  1.334e-05 ***
aphantasia:congruence        0.0186  1     0.8916    
aphantasia:color             0.6236  1     0.4297    
congruence:color             1.1352  1     0.2867    
aphantasia:congruence:color  0.2825  1     0.5951    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Table S2.4: Estimated probability of a correct answer and log-odds contrasts between groups for the accuracy in the explicit task.
Estimated Marginal Means
color Probability SE 95% CI
Uncoloured 0.97 3.15e-03 (0.97, 0.98)
Coloured 0.99 1.99e-03 (0.98, 0.99)

Marginal means estimated at color

Marginal Contrasts Analysis
Level1 Level2 Odds ratio 95% CI SE df z p
Uncoloured Coloured 0.52 (0.39, 0.69) 0.08 Inf -4.49 < .001

Marginal contrasts estimated at color p-values are uncorrected.

3 Response Times analyses

3.1 Rationale

To account for the non-normal, positively skewed distributions of the RTs, we fitted Generalized Linear Mixed Models (GLMMs) with inverse Gaussian distributions. The models were implemented in the lme4 R package and integrated in tidymodels workflows using the package multilevelmod. Models with Gamma and Gaussian distributions were also fitted and compared with the AIC and BIC to ensure that we chose the best distribution available.

The models included the Group (aphantasic, control), Congruence condition (congruent or incongruent) and Color condition (color or uncolored) along with all their two and three way interactions as fixed categorical predictors, while participants have been included as grouping factors (i.e. “random effects”). The random effect structure was chosen by fitting and comparing models with every possible combination of distribution and structure (intercept by participant, congruence or color, slope by participant on congruence and/or color) aiming for the best balance between goodness of fit and parsimony. Complex random-effects structures including various slopes on the factors failed to converge to stable and reliable estimates, hence the optimal models chosen included a single by-participant random intercept.

3.2 Model fitting

The formula of the model fitted is \(RT \sim (aphantasia + congruence + color)^3 + (1|subjectid)\).

model_formula <- rt ~ (aphantasia + congruence + color)^3 + (1|subjectid)

fit_implicit <- 
  glmer(
    formula = model_formula,
    data = df_i_rt,
    family = inverse.gaussian(link = "identity"),
    control = glmerControl(optimizer = "bobyqa")
  )

fit_explicit <- 
  glmer(
    formula = model_formula,
    data = df_e_rt,
    family = inverse.gaussian(link = "identity"),
    control = glmerControl(optimizer = "bobyqa")
  )

3.3 Model diagnostics

The quality checks of the models are displayed in Figure S3.1 and Figure S3.2 .

Code
# characteristics to check
model_checks <- c("pp_check","homogeneity", "vif", "outliers", "qq", "reqq")

check_model(
  fit_implicit, 
  checks = model_checks, 
  detrend = FALSE, 
  residual_type = "normal"
  ) |> 
  plot()

# ggsave(here("figures/checks-implicit.png"), dpi = 600)
Figure S3.1: Model assumption checks for the Generalized Linear Mixed Model fit on the RTs in the implicit task.
Code
check_model(
  fit_explicit, 
  checks = model_checks, 
  detrend = FALSE, 
  residual_type = "normal"
  ) |> 
  plot()

# ggsave(here("figures/checks-explicit.png"), dpi = 600)
Figure S3.2: Model assumption checks for the Generalized Linear Mixed Model fit on the RTs in the explicit task.

3.4 Model summaries

Table S3.1: Performance and estimates of the GLMM fitted on the implicit task data.
AIC AICc BIC R2 (cond.) R2 (marg.) ICC RMSE Sigma
-4619.06 -4619.03 -4548.26 0.01 3.47e-04 0.01 0.26 0.48
Analysis of Deviance Table (Type II Wald chisquare tests)

Response: rt
                             Chisq Df Pr(>Chisq)   
aphantasia                  0.6079  1   0.435588   
congruence                  8.6040  1   0.003354 **
color                       0.4346  1   0.509730   
aphantasia:congruence       8.5799  1   0.003399 **
aphantasia:color            0.0021  1   0.963046   
congruence:color            2.1571  1   0.141914   
aphantasia:congruence:color 1.4468  1   0.229035   
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Table S3.2: Performance and estimates of the GLMM fitted on the explicit task data.
AIC AICc BIC R2 (cond.) R2 (marg.) ICC RMSE Sigma
-2673.61 -2673.58 -2603.01 0.03 7.96e-04 0.03 0.28 0.41
Analysis of Deviance Table (Type II Wald chisquare tests)

Response: rt
                              Chisq Df Pr(>Chisq)    
aphantasia                   0.0769  1  0.7815503    
congruence                  14.5055  1  0.0001398 ***
color                       47.6344  1  5.136e-12 ***
aphantasia:congruence       10.6801  1  0.0010830 ** 
aphantasia:color             0.8183  1  0.3656672    
congruence:color             0.2153  1  0.6426749    
aphantasia:congruence:color  0.7010  1  0.4024535    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

3.5 Estimated means and contrasts

Table S3.3: Estimated means for each group in each congruence condition and contrasts between groups and conditions in the implicit task.
Group Condition Median (ms) SE df asymp.LCL asymp.UCL
Control Incongruent 669.71 19.36 Inf 631.77 707.65
Aphantasia Incongruent 676.89 15.84 Inf 645.84 707.93
Control Congruent 644.38 19.31 Inf 606.53 682.22
Aphantasia Congruent 675.05 15.83 Inf 644.02 706.08
Marginal Contrasts Analysis
Level1 Level2 Difference 95% CI SE df z p
Aphantasia Incongruent Aphantasia Congruent 1.84e-03 (-0.01, 0.01) 5.23e-03 Inf 0.35 0.725
Aphantasia Incongruent Control Congruent 0.03 (-0.02, 0.08) 0.02 Inf 1.30 0.193
Control Congruent Aphantasia Congruent -0.03 (-0.08, 0.02) 0.02 Inf -1.23 0.219
Control Incongruent Aphantasia Congruent -5.34e-03 (-0.05, 0.04) 0.02 Inf -0.21 0.831
Control Incongruent Aphantasia Incongruent -7.18e-03 (-0.06, 0.04) 0.02 Inf -0.29 0.774
Control Incongruent Control Congruent 0.03 ( 0.01, 0.04) 6.13e-03 Inf 4.13 < .001

Marginal contrasts estimated at aphantasia, congruence p-values are uncorrected.

Table S3.4: Estimated means for each group in each congruence condition and contrasts between groups and conditions in the explicit task.
Group Condition Median (ms) SE df asymp.LCL asymp.UCL
Control Incongruent 801.78 33.22 Inf 736.68 866.88
Aphantasia Incongruent 799.21 27.05 Inf 746.18 852.23
Control Congruent 770.29 33.17 Inf 705.28 835.30
Aphantasia Congruent 794.57 27.04 Inf 741.56 847.57
Marginal Contrasts Analysis
Level1 Level2 Difference 95% CI SE df z p
Aphantasia Incongruent Aphantasia Congruent 4.64e-03 (-0.01, 0.02) 5.45e-03 Inf 0.85 0.394
Aphantasia Incongruent Control Congruent 0.03 (-0.05, 0.11) 0.04 Inf 0.68 0.499
Control Congruent Aphantasia Congruent -0.02 (-0.11, 0.06) 0.04 Inf -0.57 0.570
Control Incongruent Aphantasia Congruent 7.21e-03 (-0.08, 0.09) 0.04 Inf 0.17 0.866
Control Incongruent Aphantasia Incongruent 2.57e-03 (-0.08, 0.09) 0.04 Inf 0.06 0.952
Control Incongruent Control Congruent 0.03 ( 0.02, 0.04) 6.42e-03 Inf 4.91 < .001

Marginal contrasts estimated at aphantasia, congruence p-values are uncorrected.

3.6 Visualisations

The figures below are also displayed in the main article.

Code
subj_means_im <-
  df_i_rt |> 
  group_by(subjectid, aphantasia, congruence) |>
  reframe(rt = mean(rt)*1000)

(
  plot_models_full(subj_means_im, "aphantasia", emmeans_im, y_min = 400, y_max = 1110, size = 4) +
  plot_models_zoomed(subj_means_im, "aphantasia", emmeans_im, size = 4) &
  theme(
    legend.position = "top",
    legend.title = element_blank(),
    legend.text = element_text(size = 20),
    legend.margin = margin(0, 150, 25, 0),
    axis.title.y = element_text(size = 20),
    axis.text.x = element_text(size = 18)
  )
) +
  plot_layout(
    guides = "collect",
    widths = c(1, 1.2)
  )

# ggsave(here("figures/model-implicit.png"), dpi = 600)
Figure 3.1: Subject means and model-estimated means per group and condition in the implicit task.
Code
subj_means_ex <-
  df_e_rt |> 
  group_by(subjectid, aphantasia, congruence) |>
  reframe(rt = mean(rt)*1000)

(
  plot_models_full(subj_means_ex, "aphantasia", emmeans_ex, y_min = 350, y_max = 1450, size = 4) +
  plot_models_zoomed(subj_means_ex, "aphantasia", emmeans_ex, size = 4) &
  theme(
    legend.position = "top",
    legend.title = element_blank(),
    legend.text = element_text(size = 20),
    legend.margin = margin(0, 150, 25, 0),
    axis.title.y = element_text(size = 20),
    axis.text.x = element_text(size = 18)
  )
) +
  plot_layout(
    guides = "collect",
    widths = c(1, 1.2)
  )

# ggsave(here("figures/model-explicit.png"), dpi = 600)
Figure 3.2: Subject means and model-estimated means per group and condition in the explicit task.

4 Finer sub-groups

Code
df_i_acc |> 
  select(subjectid, aphantasia, sub_group) |> 
  distinct() |> 
  group_by(aphantasia, sub_group) |> 
  count() |> 
  arrange(sub_group) |> 
  rename(Aphantasia = 1, "Sub-group" = 2, N = 3) |> 
  display()
Aphantasia Sub-group N
Control Hyperphantasia 1
Control Control 57
Aphantasia Hypophantasia 37
Aphantasia Aphantasia 48

Interestingly, we have 39 participants that did not score at floor VVIQ but between 17 and 32, a score range that Reeder & Pounder (2024) have proposed to call “hypophantasia”. However, our sample comprised only 2 hyperphantasics, i.e. participants scoring above 74 (Zeman et al., 2020). These two participants will therefore be removed from the sample before performing new analyses on the aphantasic, hypophantasic and control groups.

4.1 Questionnaires analyses

Table

Questionnaire Control Hypophantasia Aphantasia
VVIQ 53.492 ± 1.016 22.923 ± 1.26 16.049 ± 1.117
OSIQ_Object 46.09 ± 1.192 25.041 ± 1.478 23.04 ± 1.31
OSIQ_Spatial 45.467 ± 1.045 42.98 ± 1.295 39.456 ± 1.149
SUIS 36.983 ± 0.893 18.895 ± 1.107 16.102 ± 0.981
Level1 Level2 Difference CI SE t(145) p Questionnaire
Control Aphantasia 37.44 (34.45, 40.44) 1.51 24.73 < .001 VVIQ
Control Hypophantasia 30.57 (27.37, 33.76) 1.62 18.91 < .001 VVIQ
Hypophantasia Aphantasia 6.87 ( 3.54, 10.21) 1.69 4.07 < .001 VVIQ
Control Aphantasia 23.05 (19.54, 26.56) 1.78 12.98 < .001 OSIQ_Object
Control Hypophantasia 21.05 (17.30, 24.80) 1.90 11.10 < .001 OSIQ_Object
Hypophantasia Aphantasia 2.00 (-1.91, 5.91) 1.98 1.01 0.314 OSIQ_Object
Control Aphantasia 6.01 ( 2.93, 9.09) 1.56 3.86 < .001 OSIQ_Spatial
Control Hypophantasia 2.49 (-0.80, 5.77) 1.66 1.50 0.137 OSIQ_Spatial
Hypophantasia Aphantasia 3.52 ( 0.09, 6.95) 1.74 2.03 0.044 OSIQ_Spatial
Control Aphantasia 20.88 (18.25, 23.51) 1.33 15.70 < .001 SUIS
Control Hypophantasia 18.09 (15.28, 20.89) 1.42 12.74 < .001 SUIS
Hypophantasia Aphantasia 2.79 (-0.14, 5.72) 1.48 1.88 0.062 SUIS

Plot

# A tibble: 12 × 6
   Questionnaire sub_group          Mean     SE  CI_low CI_high
   <fct>         <fct>             <dbl>  <dbl>   <dbl>   <dbl>
 1 VVIQ          Control        5.86e- 1 0.0158  0.555   0.617 
 2 VVIQ          Hypophantasia  1.09e- 1 0.0196  0.0698  0.147 
 3 VVIQ          Aphantasia    -4.44e-16 0.0173 -0.0342  0.0342
 4 OSIQ_Object   Control        5.18e- 1 0.0198  0.479   0.557 
 5 OSIQ_Object   Hypophantasia  1.68e- 1 0.0245  0.119   0.216 
 6 OSIQ_Object   Aphantasia     1.34e- 1 0.0217  0.0909  0.176 
 7 OSIQ_Spatial  Control        5.09e- 1 0.0174  0.474   0.543 
 8 OSIQ_Spatial  Hypophantasia  4.68e- 1 0.0216  0.425   0.510 
 9 OSIQ_Spatial  Aphantasia     4.05e- 1 0.0191  0.368   0.443 
10 SUIS          Control        5.22e- 1 0.0186  0.485   0.558 
11 SUIS          Hypophantasia  1.45e- 1 0.0230  0.0992  0.190 
12 SUIS          Aphantasia     8.33e- 2 0.0203  0.0431  0.124 
Code
df_q_norm |> 
  filter(sub_group != "Hyperphantasia") |>
  
  # --------------------- Long format first
  pivot_longer(
    cols = c(VVIQ:SUIS),
    names_to = "Questionnaire",
    values_to = "Score"
  ) |>
  mutate(
    Questionnaire = fct_relevel(
      Questionnaire, 
      c("VVIQ", "SUIS", "OSIQ_Object", "OSIQ_Spatial")
    )) |> 
  
  # --------------------- Plotting 
  ggplot(aes(
    x = Questionnaire, 
    y = Score, 
    fill = sub_group, 
    color = sub_group
    )) +
  
  # accentuation of the median line at 0.5
  geom_hline(
    yintercept = .5,
    linetype = 1,
    color = "grey30",
    alpha = .2
  ) +
  
  # ---------------- Scores
  # violin shapes for the distributions and quantiles
  geom_violin(
    position = position_dodge(dw),
    alpha = .1,
    draw_quantiles = c(.25, .5, .75)
  ) +
  # points for means and lines for CIs
  geom_pointrange(
    data = norm_means_finer,
    aes(
      x = Questionnaire,
      y = Mean,
      ymin = CI_low,
      ymax = CI_high,
      color = sub_group
    ),
    size = .75,
    linewidth = 1,
    position = position_dodge(dw)
  ) +
  
  # ---------------- Lines
  geom_vline(
    aes(xintercept = stage(Questionnaire, after_scale = 1.5)),
    linetype = 3
  ) +
  geom_vline(
    aes(xintercept = stage(Questionnaire, after_scale = 2.5)),
    linetype = 3
  ) +
  # dotted line
  geom_vline(
    aes(xintercept = stage(Questionnaire, after_scale = 3.5)),
    linetype = 3
  ) +
  
  # --------------- Significance
  # VVIQ control vs others
  plot_significance_labels(label = "***", size = 7,
    x_star = 0.83, y_star = .93,
    x_line = 0.66, x_line_end = 1,
    y_line = .92
  ) +
  geom_segment(
    x = 0.66, xend = 1.34, 
    y = .91, yend = .91, linewidth = .5, color = "black") +
  # VVIQ hypo vs aph
  plot_significance_labels(label = "***", size = 7,
    x_star = 1.17, y_star = .39,
    x_line = 1, x_line_end = 1.34,
    y_line = .38
  ) +
  
  # SUIS control vs others
  plot_significance_labels(label = "***", size = 7,
    x_star = 1.83, y_star = .93,
    x_line = 1.66, x_line_end = 2,
    y_line = .92
  ) +
  geom_segment(
    x = 1.66, xend = 2.34, 
    y = .91, yend = .91, linewidth = .5, color = "black") +
  # SUIS hypo vs aph
  plot_significance_labels(label = "*", size = 7,
    x_star = 2.17, y_star = .39,
    x_line = 2, x_line_end = 2.34,
    y_line = .38
  ) +
  
  # OSIQ-O control vs others
  plot_significance_labels(label = "***", size = 7,
    x_star = 2.83, y_star = .93,
    x_line = 2.66, x_line_end = 3,
    y_line = .92
  ) +
  geom_segment(
    x = 2.66, xend = 3.34, 
    y = .91, yend = .91, linewidth = .5, color = "black") +
  
  # OSIQ-S control vs aph only
  plot_significance_labels(label = "***", size = 7,
    x_star = 4, y_star = .84,
    x_line = 3.66, x_line_end = 4.34,
    y_line = .83
  ) +
  # OSIQ-S hypo vs aph
  plot_significance_labels(label = "*", size = 7,
    x_star = 4.17, y_star = .78,
    x_line = 4, x_line_end = 4.34,
    y_line = .77
  ) +
  
  # ----------------------------- Aesthetics 
  scale_color_okabeito(name = "Group:  ", labels = c(" Control   ", " Hypophantasia   ", " Aphantasia")) +
  scale_fill_okabeito(name = "Group:  ", labels  = c(" Control   ", " Hypophantasia   ", " Aphantasia")) +
  scale_x_discrete(
    name = "",
    labels = c("VVIQ", "SUIS", "OSIQ-Object", "OSIQ-Spatial"),
    expand = expansion(mult = c(0, 0))
  ) +
  scale_y_continuous(
    name = "Standardized score",
    breaks = breaks_pretty(8),
    expand = expansion(mult = c(0.05, 0.1))
  ) +
  theme(
    panel.grid.major.x = element_blank(),
    panel.grid.major.y = element_line(),
    axis.text.x  = element_text(size = txt),
    axis.title.y = element_text(size = txt),
    legend.title = element_text(size = txt_legend),
    legend.text  = element_text(size = txt_legend),
    legend.position = "top"
    )
Code
ggsave(here("figures/questionnaires-finer.png"), dpi = 600)

Figure S4.1

4.2 Response Times analysis

4.3 Model fitting

Code
model_formula_finer <- rt ~ (sub_group + congruence + color)^3 + (1|subjectid)

fit_finer_i <- 
  glmer(
    formula = model_formula_finer,
    data = df_i_finer,
    family = inverse.gaussian(link = "identity"),
    control = glmerControl(optimizer = "bobyqa")
  )

fit_finer_e <-
  glmer(
    formula = model_formula_finer,
    data = df_e_finer,
    family = inverse.gaussian(link = "identity"),
    control = glmerControl(optimizer = "bobyqa")
  )

4.4 Model diagnostics

Code
# characteristics to check
model_checks <- c("pp_check","homogeneity", "vif", "outliers", "qq", "reqq")

check_model(
  fit_finer_i, 
  checks = model_checks, 
  detrend = FALSE, 
  residual_type = "normal"
  ) |> 
  plot()

# ggsave(here("figures/checks-finer-implicit.png"), dpi = 600)

check_model(
  fit_finer_e, 
  checks = model_checks, 
  detrend = FALSE, 
  residual_type = "normal"
  ) |> 
  plot()

# ggsave(here("figures/checks-finer-explicit.png"), dpi = 600)
Figure S4.2: Model assumption checks for the Generalized Linear Mixed Model fit on the RTs in the implicit task with finer sub-groups.
Figure S4.3: Model assumption checks for the Generalized Linear Mixed Model fit on the RTs in the explicit task with finer sub-groups.

4.5 Model summaries

Code
model_performance(fit_finer_i) |> display()
AIC AICc BIC R2 (cond.) R2 (marg.) ICC RMSE Sigma
-4629.18 -4629.13 -4530.16 0.02 6.43e-04 0.01 0.26 0.48
Code
# model_parameters(fit_finer_i) |> display()

Anova(fit_finer_i)
Analysis of Deviance Table (Type II Wald chisquare tests)

Response: rt
                             Chisq Df Pr(>Chisq)   
sub_group                   1.4143  2   0.493042   
congruence                  8.7113  1   0.003162 **
color                       0.5361  1   0.464064   
sub_group:congruence       13.2326  2   0.001338 **
sub_group:color             1.2212  2   0.543029   
congruence:color            1.9224  1   0.165588   
sub_group:congruence:color  1.7589  2   0.415017   
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Code
model_performance(fit_finer_e) |> display()
AIC AICc BIC R2 (cond.) R2 (marg.) ICC RMSE Sigma
-2549.41 -2549.36 -2450.78 0.03 6.89e-04 0.03 0.28 0.41
Code
# model_parameters(fit_finer_e) |> display()

Anova(fit_finer_e)
Analysis of Deviance Table (Type II Wald chisquare tests)

Response: rt
                             Chisq Df Pr(>Chisq)    
sub_group                   0.0238  2  0.9881837    
congruence                 11.4280  1  0.0007234 ***
color                      44.0495  1  3.202e-11 ***
sub_group:congruence        8.1752  2  0.0167794 *  
sub_group:color             0.4794  2  0.7868834    
congruence:color            0.2415  1  0.6230973    
sub_group:congruence:color  2.2646  2  0.3222926    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

4.6 Estimated means and contrasts

Table S4.1: Marginal Contrasts Analysis
Condition Sub-group Median (ms) SE df asymp.LCL asymp.UCL
Incongruent Control 667.63 19.48 Inf 629.45 705.82
Congruent Control 642.01 19.43 Inf 603.92 680.10
Incongruent Hypophantasia 668.39 24.03 Inf 621.28 715.49
Congruent Hypophantasia 654.24 24.00 Inf 607.20 701.28
Incongruent Aphantasia 682.92 20.92 Inf 641.92 723.92
Congruent Aphantasia 691.12 20.93 Inf 650.10 732.13
Level1 Level2 Difference 95% CI SE df z p
Congruent Control Congruent Aphantasia -0.05 (-0.11, 0.01) 0.03 Inf -1.72 0.085
Congruent Control Congruent Hypophantasia -0.01 (-0.07, 0.05) 0.03 Inf -0.40 0.692
Congruent Control Incongruent Aphantasia -0.04 (-0.10, 0.01) 0.03 Inf -1.43 0.152
Congruent Control Incongruent Hypophantasia -0.03 (-0.09, 0.03) 0.03 Inf -0.85 0.393
Congruent Hypophantasia Congruent Aphantasia -0.04 (-0.10, 0.03) 0.03 Inf -1.16 0.247
Congruent Hypophantasia Incongruent Aphantasia -0.03 (-0.09, 0.03) 0.03 Inf -0.90 0.367
Incongruent Aphantasia Congruent Aphantasia -8.19e-03 (-0.02, 0.01) 7.04e-03 Inf -1.16 0.244
Incongruent Control Congruent Aphantasia -0.02 (-0.08, 0.03) 0.03 Inf -0.82 0.411
Incongruent Control Congruent Control 0.03 ( 0.01, 0.04) 6.15e-03 Inf 4.17 < .001
Incongruent Control Congruent Hypophantasia 0.01 (-0.05, 0.07) 0.03 Inf 0.43 0.665
Incongruent Control Incongruent Aphantasia -0.02 (-0.07, 0.04) 0.03 Inf -0.54 0.592
Incongruent Control Incongruent Hypophantasia -7.55e-04 (-0.06, 0.06) 0.03 Inf -0.02 0.981
Incongruent Hypophantasia Congruent Aphantasia -0.02 (-0.09, 0.04) 0.03 Inf -0.71 0.475
Incongruent Hypophantasia Congruent Hypophantasia 0.01 ( 0.00, 0.03) 7.79e-03 Inf 1.82 0.069
Incongruent Hypophantasia Incongruent Aphantasia -0.01 (-0.08, 0.05) 0.03 Inf -0.46 0.648

Marginal contrasts estimated at congruence, sub_group p-values are uncorrected.

Table S4.2: Marginal Contrasts Analysis
Condition Sub-group Median (ms) SE df asymp.LCL asymp.UCL
Incongruent Control 805.25 33.85 Inf 738.91 871.59
Congruent Control 776.89 33.81 Inf 710.64 843.15
Incongruent Hypophantasia 799.65 40.77 Inf 719.74 879.56
Congruent Hypophantasia 796.06 40.76 Inf 716.17 875.95
Incongruent Aphantasia 798.72 36.34 Inf 727.49 869.96
Congruent Aphantasia 793.26 36.33 Inf 722.05 864.47
Level1 Level2 Difference 95% CI SE df z p
Congruent Control Congruent Aphantasia -0.02 (-0.11, 0.08) 0.05 Inf -0.33 0.742
Congruent Control Congruent Hypophantasia -0.02 (-0.12, 0.08) 0.05 Inf -0.36 0.717
Congruent Control Incongruent Aphantasia -0.02 (-0.12, 0.08) 0.05 Inf -0.44 0.660
Congruent Control Incongruent Hypophantasia -0.02 (-0.13, 0.08) 0.05 Inf -0.43 0.667
Congruent Hypophantasia Congruent Aphantasia 2.81e-03 (-0.10, 0.11) 0.05 Inf 0.05 0.959
Congruent Hypophantasia Incongruent Aphantasia -2.66e-03 (-0.11, 0.10) 0.05 Inf -0.05 0.961
Incongruent Aphantasia Congruent Aphantasia 5.46e-03 (-0.01, 0.02) 7.44e-03 Inf 0.73 0.463
Incongruent Control Congruent Aphantasia 0.01 (-0.09, 0.11) 0.05 Inf 0.24 0.809
Incongruent Control Congruent Control 0.03 ( 0.02, 0.04) 6.58e-03 Inf 4.31 < .001
Incongruent Control Congruent Hypophantasia 9.19e-03 (-0.09, 0.11) 0.05 Inf 0.17 0.862
Incongruent Control Incongruent Aphantasia 6.53e-03 (-0.09, 0.10) 0.05 Inf 0.13 0.895
Incongruent Control Incongruent Hypophantasia 5.60e-03 (-0.10, 0.11) 0.05 Inf 0.11 0.916
Incongruent Hypophantasia Congruent Aphantasia 6.39e-03 (-0.10, 0.11) 0.05 Inf 0.12 0.907
Incongruent Hypophantasia Congruent Hypophantasia 3.59e-03 (-0.01, 0.02) 8.01e-03 Inf 0.45 0.654
Incongruent Hypophantasia Incongruent Aphantasia 9.30e-04 (-0.11, 0.11) 0.05 Inf 0.02 0.986

Marginal contrasts estimated at congruence, sub_group p-values are uncorrected.

Code
subj_means_finer_im <-
  df_i_finer |> 
  group_by(subjectid, sub_group, congruence) |>
  reframe(rt = mean(rt)*1000)

(
  plot_models_full(subj_means_finer_im, "sub_group", emmeans_finer_im, size = 4, dw = .6) +
  plot_models_zoomed(subj_means_finer_im, "sub_group", emmeans_finer_im, size = 4) &
  theme(
    legend.position = "top",
    legend.title = element_blank(),
    legend.text = element_text(size = 20),
    legend.margin = margin(0, 150, 25, 0),
    axis.title.y = element_text(size = 20),
    axis.text.x = element_text(size = 18)
  )
) +
  plot_layout(
    guides = "collect",
    widths = c(1, 1.2)
  )

# ggsave(here("figures/model-implicit-finer.png"), dpi = 600)
Figure 4.1
Code
subj_means_finer_ex <-
  df_e_finer |> 
  group_by(subjectid, sub_group, congruence) |>
  reframe(rt = mean(rt)*1000)

(
  plot_models_full(subj_means_finer_ex, "sub_group", emmeans_finer_ex, y_min = 350, y_max = 1450, size = 4, dw = .6) +
  plot_models_zoomed(subj_means_finer_ex, "sub_group", emmeans_finer_ex, size = 4) &
  theme(
    legend.position = "top",
    legend.title = element_blank(),
    legend.text = element_text(size = 20),
    legend.margin = margin(0, 150, 25, 0),
    axis.title.y = element_text(size = 20),
    axis.text.x = element_text(size = 18)
  )
) +
  plot_layout(
    guides = "collect",
    widths = c(1, 1.2)
  )

# ggsave(here("figures/model-explicit-finer.png"), dpi = 600)
Figure 4.2

5 Bayesian modelling

We used Bayesian hypothesis testing to assess the congruence effect separately for each group. Thus, for each subset of the data (control, aphantasia, hypophantasia, aphantasia without hypo., control without hyperphantasia), we fitted a model with the formula \(RT \sim (congruence + color)^3 + (1|subjectid)\) and compared the models with and without the congruence effect using Bayes Factors.

formula <- bf(rt ~ congruence * color + (1 | subjectid))

We used more sensible priors than the default ones as regularizing priors to avoid overfitting.

# to see the default priors:
# get_prior(formula, data = df_i_rt, family = shifted_lognormal())
# need to define better priors for the intercept, sigma, b, and sd

prior <- c(
  prior(normal(-1, 0.5), class = 'Intercept'),  # around exp(-1) = 0.36 secs
  prior(normal(0.4, 0.3), class = 'sigma'), # SD of individual rts in log-units
  prior(normal(0, 0.3), class = 'b'), # around exp(-1) - exp(-1 + 0.3) = 150 ms 
  prior(normal(0.3, 0.1), class = 'sd')  # some variability between participants
)

Bayesian models were fitted using the brms package with the cmdstanr backend. We used parallel processing to fit the models. We aimed for 40000 post-warmup iterations to have sufficient draws to compute reliable Bayes Factors. Using a computer with 20 cores available for parallel processing, we could fit 20 chains of 3000 iterations with 1000 warmup iterations. Each model fitted in approximately 1 minute. Model fits are saved as .rds files for reproducibility and can be found on OSF in the analysis project, under the data/r-data-structures folder.

Code
# detecting the number of cores to use
n_cores <- parallel::detectCores() - 4

# defining the number of iterations per chain (+ 1000 warm-up)
n_iter <- ceiling(40000 / n_cores) + 1000

# cmdstanr options
options(cmdstanr_warn_inits = FALSE)
Fitting the first model
# Implicit task, aphantasia group ---------------------------------------------
fit_implicit_aph <- 
  brm(
    formula = formula,
    data = df_i_rt |> filter(aphantasia == "Aphantasia"),
    family = shifted_lognormal(),
    prior = prior,
    sample_prior = TRUE,
    chains = n_cores,
    cores  = n_cores,
    iter   = n_iter,
    warmup = 1000,
    refresh = 5,
    backend = "cmdstanr",
    stan_model_args = list(stanc_options = list("O1")),
    save_pars = save_pars(all = TRUE),
    file = here("data/r-data-structures/brms-model-implicit-aph.rds"),
    file_compress = "xz"
  )

To save compilation time, we used the brms function update to use the first compiled model as a template for all the others.

Updating the first model for the other groups
# Implicit task models ----------------------------------------------------

# Control group ---------------------------------------------
fit_implicit_con <-
  # the `custom_update` function can be found in the `scripts/_functions.R` file
  custom_update(fit_implicit_aph,
    data = df_i_rt |> filter(aphantasia == "Control"),
    file = "data/r-data-structures/brms-model-implicit-con.rds"
  )

# Finer aphantasia group -------------------------------------
fit_implicit_finer_aph <- 
  custom_update(fit_implicit_aph,
    data = df_i_finer |> filter(sub_group == "Aphantasia"),
    file = "data/r-data-structures/brms-model-implicit-finer-aph.rds"
  )

# Hypophantasia group -------------------------------------
fit_implicit_hypo <- 
  custom_update(fit_implicit_aph,
    data = df_i_finer |> filter(sub_group == "Hypophantasia"),
    file = "data/r-data-structures/brms-model-implicit-hypo.rds"
  )

# Finer control group -------------------------------------
fit_implicit_finer_con <- 
  custom_update(fit_implicit_aph,
    data = df_i_finer |> filter(sub_group == "Control"),
    file = "data/r-data-structures/brms-model-implicit-finer-con.rds"
  )


# Explicit task models -----------------------------------------------------

# Aphantasia group ---------------------------------------------
fit_explicit_aph <- 
  custom_update(fit_implicit_aph,
    data = df_e_rt |> filter(aphantasia == "Aphantasia"),
    file = "data/r-data-structures/brms-model-explicit-aph.rds"
  )

# Control group ---------------------------------------------
fit_explicit_con <- 
  custom_update(fit_implicit_aph,
    data = df_e_rt |> filter(aphantasia == "Control"),
    file = "data/r-data-structures/brms-model-explicit-con.rds"
  )

# Finer aphantasia group -------------------------------------
fit_explicit_finer_aph <- 
  custom_update(fit_implicit_aph,
    data = df_e_finer |> filter(sub_group == "Aphantasia"),
    file = "data/r-data-structures/brms-model-explicit-finer-aph.rds"
  )

# Hypophantasia group -------------------------------------
fit_explicit_hypo <- 
  custom_update(fit_implicit_aph,
    data = df_e_finer |> filter(sub_group == "Hypophantasia"),
    file = "data/r-data-structures/brms-model-explicit-hypo.rds"
  )

# Finer control group -------------------------------------
fit_explicit_finer_con <- 
  custom_update(fit_implicit_aph,
    data = df_e_finer |> filter(sub_group == "Control"),
    file = "data/r-data-structures/brms-model-explicit-finer-con.rds"
  )

We finally compute Bayes Factor in favour of the null model of an absence of congruence effect for each group.

Implicit task models ------------------------------------------------
Aphantasia group, evidence against an implicit congruence effect: 
 BF_01 = 14.12439 
Control group, evidence against an implicit congruence effect: 
 BF_01 = 2.014823e-06 
Finer aphantasia group, evidence against an implicit congruence effect: 
 BF_01 = 12.59357 
Hypophantasia group, evidence against an implicit congruence effect: 
 BF_01 = 2.413134 
Finer control group, evidence against an implicit congruence effect: 
 BF_01 = 0.004105608 

Explicit task models ------------------------------------------------
Aphantasia group, evidence against an explicit congruence effect: 
 BF_01 = 12.08795 
Control group, evidence against an explicit congruence effect: 
 BF_01 = 0.002964782 
Finer aphantasia group, evidence against an explicit congruence effect: 
 BF_01 = 11.78268 
Hypophantasia group, evidence against an explicit congruence effect: 
 BF_01 = 9.81433 
Finer control group, evidence against an explicit congruence effect: 
 BF_01 = 2.179724e-06 

     

═════════════════════════════════════════════════════════════════════════
Analyses were conducted using the R Statistical language (version 4.4.1; R Core
Team, 2024) on Windows 11 x64 (build 22631)
Packages used:
  - quarto (version 1.4.4; Allaire J, Dervieux C, 2024)
  - qqplotr (version 0.0.6; Almeida A et al., 2018)
  - lme4 (version 1.1.35.5; Bates D et al., 2015)
  - Matrix (version 1.7.0; Bates D et al., 2024)
  - effectsize (version 0.8.9; Ben-Shachar MS et al., 2020)
  - brms (version 2.21.0; Bürkner P, 2017)
  - ggbeeswarm (version 0.7.2; Clarke E et al., 2023)
  - Rcpp (version 1.0.12; Eddelbuettel D et al., 2024)
  - car (version 3.1.2; Fox J, Weisberg S, 2019)
  - carData (version 3.0.5; Fox J et al., 2022)
  - cmdstanr (version 0.8.1; Gabry J et al., 2024)
  - bayesplot (version 1.11.1; Gabry J, Mahr T, 2024)
  - statmod (version 1.5.0; Giner G, Smyth GK, 2016)
  - simr (version 1.0.7; Green P, MacLeod CJ, 2016)
  - lubridate (version 1.9.3; Grolemund G, Wickham H, 2011)
  - ggpubr (version 0.6.0; Kassambara A, 2023)
  - tidybayes (version 3.0.6; Kay M, 2023)
  - labelled (version 2.13.0; Larmarange J, 2024)
  - emmeans (version 1.10.3; Lenth R, 2024)
  - parameters (version 0.22.0; Lüdecke D et al., 2020)
  - performance (version 0.12.0; Lüdecke D et al., 2021)
  - easystats (version 0.7.2; Lüdecke D et al., 2022)
  - see (version 0.8.4; Lüdecke D et al., 2021)
  - insight (version 0.20.1; Lüdecke D et al., 2019)
  - bayestestR (version 0.13.2; Makowski D et al., 2019)
  - modelbased (version 0.8.8; Makowski D et al., 2020)
  - report (version 0.5.8; Makowski D et al., 2023)
  - correlation (version 0.8.5; Makowski D et al., 2022)
  - latex2exp (version 0.9.6; Meschiari S, 2022)
  - here (version 1.0.1; Müller K, 2020)
  - tibble (version 3.2.1; Müller K, Wickham H, 2023)
  - datawizard (version 0.11.0; Patil I et al., 2022)
  - patchwork (version 1.2.0; Pedersen T, 2024)
  - R (version 4.4.1; R Core Team, 2024)
  - pacman (version 0.5.1; Rinker TW, Kurkiewicz D, 2018)
  - openxlsx (version 4.2.5.2; Schauberger P, Walker A, 2023)
  - ggplot2 (version 3.5.1; Wickham H, 2016)
  - forcats (version 1.0.0; Wickham H, 2023)
  - stringr (version 1.5.1; Wickham H, 2023)
  - tidyverse (version 2.0.0; Wickham H et al., 2019)
  - readxl (version 1.4.3; Wickham H, Bryan J, 2023)
  - dplyr (version 1.1.4; Wickham H et al., 2023)
  - purrr (version 1.0.2; Wickham H, Henry L, 2023)
  - readr (version 2.1.5; Wickham H et al., 2024)
  - scales (version 1.3.0; Wickham H et al., 2023)
  - tidyr (version 1.3.1; Wickham H et al., 2024)
═════════════════════════════════════════════════════════════════════════

References

Reeder, R., & Pounder, Z. (2024). Non-visual spatial strategies are efficient for maintaining precise information in visual working memor. https://doi.org/10.31234/osf.io/gx2dv
Zeman, A., Milton, F., Della Sala, S., Dewar, M., Frayling, T., Gaddum, J., Hattersley, A., Heuerman-Williamson, B., Jones, K., MacKisack, M., & Winlove, C. (2020). Phantasia psychological significance of lifelong visual imagery vividness extremes. Cortex, 130, 426–440. https://doi.org/10.1016/j.cortex.2020.04.003